﻿using IPlugin;
using IPlugin.Attributes;
using Mohe.Scada.Util.Models;
using NLog;
using System.IO.Ports;

namespace AteqDriver
{
    public class AteqDriver : IDriver
    {
        private static Logger _logger = LogManager.GetLogger(nameof(AteqDriver));
        private SerialPort sp1;


        public bool IsConnected => sp1 != null && sp1.IsOpen;

        private readonly string _device;

        #region 配置参数

        [ConfigParameter("设备Id")]
        public int DeviceId { get; set; }



        [ConfigParameter("串口名")]
        public string PortName { get; set; } = "COM1";

        [ConfigParameter("波特率")]
        public int BaudRate { get; set; } = 9600;

        [ConfigParameter("数据位")]
        public int DataBits { get; set; } = 8;

        [ConfigParameter("校验位")]
        public Parity Parity { get; set; } = Parity.Even;

        [ConfigParameter("停止位")]
        public StopBits StopBits { get; set; } = StopBits.One;

        [ConfigParameter("从站号")]
        public byte SlaveAddress { get; set; } = 1;

        [ConfigParameter("超时时间ms")]
        public int TimeOut { get; set; } = 3000;

        [ConfigParameter("最小通讯周期ms")]
        public int MinPeriod { get; set; } = 3000;

        #endregion


        /// <summary>
        /// 反射构造函数
        /// </summary>
        /// <param name="device"></param>
        /// <param name="logger"></param>
        public AteqDriver(string device)
        {
            _device = device;
            sp1 = new SerialPort();
            _logger.Info($"Device:[{_device}],Create()");
        }
        public bool Close()
        {
            try
            {
                sp1?.Close();
                _logger.Info($"Device:[{_device}],Close()");
                return !IsConnected;
            }
            catch (Exception ex)
            {
                _logger.Error($"Device:[{_device}],Close(),Error", ex);
                return false;
            }
        }

        public bool Connect()
        {
            try
            {
                sp1 = new SerialPort(PortName, BaudRate, Parity, DataBits, StopBits);
                sp1.ReadTimeout = TimeOut;
                sp1.WriteTimeout = TimeOut;
                sp1.DtrEnable = true;
                sp1.RtsEnable = true;
                sp1.Open();
            }
            catch (Exception ex)
            {

                _logger.Error(ex, "connect error");
            }
            return IsConnected;
        }
        public static byte[] CRC16(byte[] data)
        {
            int len = data.Length;
            if (len > 0)
            {
                ushort crc = 0xFFFF;

                for (int i = 0; i < len; i++)
                {
                    crc = (ushort)(crc ^ (data[i]));
                    for (int j = 0; j < 8; j++)
                    {
                        crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1);
                    }
                }
                byte hi = (byte)((crc & 0xFF00) >> 8);  //高位置
                byte lo = (byte)(crc & 0x00FF);         //低位置

                return new byte[] { hi, lo };
            }
            return new byte[] { 0, 0 };
        }

        /// <summary>
        ///  3~6 下限值
        ///  7~10 上限值
        /// </summary>
        /// <param name="ioArg"></param>
        /// <returns></returns>
        [Method("取上下限", description: "取上下限")]

        public DriverReturnValueModel ReadMaxfillMinfill(DriverAddressIoArgModel ioArg)
        {
            var ret = new DriverReturnValueModel { StatusType = EnumVariableStatus.Good };

            if (IsConnected)
            {
                try
                {
                    byte[] 数组1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                    byte[] 数组2 = new byte[] { 0x00, 0x00 };
                    byte[] 数组3 = new byte[] { 0x00, 0x03, 0x60, 0x32, 0x00, 0x04, 0x00, 0x00, };
                    byte b = SlaveAddress;
                    数组1[0] = b;
                    数组1[1] = 0x03;
                    数组1[2] = 0x60;
                    数组1[3] = 0x32;
                    数组1[4] = 0x00;
                    数组1[5] = 0x04;
                    数组2 = CRC16(数组1);
                    数组3[0] = b;
                    数组3[6] = 数组2[1];
                    数组3[7] = 数组2[0];
                    sp1.Write(数组3, 0, 数组3.Length);
                    Thread.Sleep(50);
                    Byte[] receivedData = new Byte[sp1.BytesToRead];
                    sp1.Read(receivedData, 0, receivedData.Length);
                    if (receivedData[1] == 0x03)
                    {
                        ret.Value = receivedData;
                        sp1.DiscardInBuffer();
                    }
                    else
                    {
                        sp1.DiscardInBuffer();
                    }
                }
                catch (Exception ex)
                {
                    ret.StatusType = EnumVariableStatus.Bad;
                    ret.Message = $"读取失败,{ex.Message}";
                    _logger.Error(ex, $"读取失败{ioArg.Address}");
                }
            }
            else
            {
                ret.StatusType = EnumVariableStatus.Bad;
                ret.Message = "连接失败";
            }

            return ret;

        }

        /// <summary>
        /// 3~6 充气时间
        /// 7~10 保压时间
        /// 11~14 测试时间
        /// </summary>
        /// <param name="ioArg"></param>
        /// <returns></returns>
        [Method("取测试时间", description: "取测试时间")]
        public DriverReturnValueModel ReadTestTime(DriverAddressIoArgModel ioArg)
        {
            var ret = new DriverReturnValueModel { StatusType = EnumVariableStatus.Good };

            if (IsConnected)
            {
                try
                {
                    byte[] 数组1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                    byte[] 数组2 = new byte[] { 0x00, 0x00 };
                    byte[] 数组3 = new byte[] { 0x00, 0x03, 0x60, 0x01, 0x00, 0x06, 0x00, 0x00, };
                    byte b = SlaveAddress;
                    数组1[0] = b;
                    数组1[1] = 0x03;
                    数组1[2] = 0x60;
                    数组1[3] = 0x01;
                    数组1[4] = 0x00;
                    数组1[5] = 0x06;
                    数组2 = CRC16(数组1);
                    数组3[0] = b;
                    数组3[6] = 数组2[1];
                    数组3[7] = 数组2[0];
                    sp1.Write(数组3, 0, 数组3.Length);
                    Thread.Sleep(50);
                    Byte[] receivedData = new Byte[sp1.BytesToRead];
                    sp1.Read(receivedData, 0, receivedData.Length);
                    if (receivedData[1] == 0x03)
                    {
                        ret.Value = receivedData;
                        sp1.DiscardInBuffer();
                    }
                    else
                    {
                        sp1.DiscardInBuffer();
                    }
                }
                catch (Exception ex)
                {
                    ret.StatusType = EnumVariableStatus.Bad;
                    ret.Message = $"读取失败,{ex.Message}";
                    _logger.Error(ex, $"读取失败{ioArg.Address}");
                }
            }
            else
            {
                ret.StatusType = EnumVariableStatus.Bad;
                ret.Message = "连接失败";
            }

            return ret;
        }
        /// <summary>
        ///    3-程序号
        ///    9~10 实时结果  比特位0-OK 1 TNG 2 RNG 3 报警 4 压力Error 5 结束
        ///    11~12 步骤
        ///    13~16 压力值
        ///    17~20 压力值单位
        ///    21~24 泄露值
        ///    25~28 泄露值单位
        ///    
        /// </summary>
        /// <param name="ioArg"></param>
        /// <returns></returns>
        [Method("取实时测试结果", description: "取实时测试结果")]
        public DriverReturnValueModel ReadRealResult(DriverAddressIoArgModel ioArg)
        {
            var ret = new DriverReturnValueModel { StatusType = EnumVariableStatus.Good };

            if (IsConnected)
            {
                try
                {
                    byte[] 最后结果1 = new byte[] { 0x00, 0x03, 0x00, 0x30, 0x00, 0x0D };
                    byte[] 最后结果2 = new byte[] { 0x00, 0x00 };
                    byte[] 最后结果3 = new byte[] { 0x00, 0x03, 0x00, 0x30, 0x00, 0x0D, 0x00, 0x00 };
                    byte b = SlaveAddress;
                    最后结果1[0] = b;
                    最后结果1[1] = 0x03;
                    最后结果1[2] = 0x00;
                    最后结果1[3] = 0x30;
                    最后结果1[4] = 0x00;
                    最后结果1[5] = 0x0D;
                    最后结果2 = CRC16(最后结果1);
                    最后结果3[0] = b;
                    最后结果3[6] = 最后结果2[1];
                    最后结果3[7] = 最后结果2[0];
                    sp1.Write(最后结果3, 0, 最后结果3.Length);
                    Thread.Sleep(50);
                    Byte[] receivedData = new Byte[sp1.BytesToRead];
                    sp1.Read(receivedData, 0, receivedData.Length);
                    if (receivedData[1] == 0x03)
                    {
                        ret.Value = receivedData;
                        sp1.DiscardInBuffer();
                    }
                    else
                    {
                        sp1.DiscardInBuffer();
                    }
                }
                catch (Exception ex)
                {
                    ret.StatusType = EnumVariableStatus.Bad;
                    ret.Message = $"读取失败,{ex.Message}";
                    _logger.Error(ex, $"读取失败{ioArg.Address}");
                }
            }
            else
            {
                ret.StatusType = EnumVariableStatus.Bad;
                ret.Message = "连接失败";
            }

            return ret;
        }

        /// <summary>
        /// 3-程序号
        /// 7~8 测试结果 1合格 2-测试端不合格 4标准端不合格 8压力报警
        /// 9~10 报警结果
        /// 11~14 压力值
        /// 15~18 压力单位
        /// 19~22 泄露值
        /// 23~26 泄露单位
        /// 
        /// </summary>
        /// <param name="ioArg"></param>
        /// <returns></returns>
        [Method("取最后测试结果", description: "取最后测试结果")]
        public DriverReturnValueModel ReadFinalResult(DriverAddressIoArgModel ioArg)
        {
            var ret = new DriverReturnValueModel { StatusType = EnumVariableStatus.Good };

            if (IsConnected)
            {
                try
                {
                    byte[] 最后结果1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                    byte[] 最后结果2 = new byte[] { 0x00, 0x00 };
                    byte[] 最后结果3 = new byte[] { 0x00, 0x03, 0x00, 0x11, 0x00, 0x0C, 0x00, 0x00 };
                    byte b = SlaveAddress;
                    最后结果1[0] = b;
                    最后结果1[1] = 0x03;
                    最后结果1[2] = 0x00;
                    最后结果1[3] = 0x11;
                    最后结果1[4] = 0x00;
                    最后结果1[5] = 0x0C;
                    最后结果2 = CRC16(最后结果1);
                    最后结果3[0] = b;
                    最后结果3[6] = 最后结果2[1];
                    最后结果3[7] = 最后结果2[0];
                    sp1.Write(最后结果3, 0, 最后结果3.Length);
                    Thread.Sleep(50);
                    Byte[] receivedData = new Byte[sp1.BytesToRead];
                    sp1.Read(receivedData, 0, receivedData.Length);
                    if (receivedData[1] == 0x03)
                    {
                        ret.Value = receivedData;
                        sp1.DiscardInBuffer();
                    }
                    else
                    {
                        sp1.DiscardInBuffer();
                    }
                }
                catch (Exception ex)
                {
                    ret.StatusType = EnumVariableStatus.Bad;
                    ret.Message = $"读取失败,{ex.Message}";
                    _logger.Error(ex, $"读取失败{ioArg.Address}");
                }
            }
            else
            {
                ret.StatusType = EnumVariableStatus.Bad;
                ret.Message = "连接失败";
            }

            return ret;
        }

        /// <summary>
        /// 3~6标准泄露值
        /// </summary>
        /// <param name="ioArg"></param>
        /// <returns></returns>
        [Method("取泄露标准", description: "取泄露标准")]
        public DriverReturnValueModel ReadLeakStandard(DriverAddressIoArgModel ioArg)
        {
            var ret = new DriverReturnValueModel { StatusType = EnumVariableStatus.Good };

            if (IsConnected)
            {
                try
                {
                    byte[] 数组1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                    byte[] 数组2 = new byte[] { 0x00, 0x00 };
                    byte[] 数组3 = new byte[] { 0x00, 0x03, 0x60, 0x3C, 0x00, 0x06, 0x00, 0x00, };
                    byte b = SlaveAddress;
                    数组1[0] = b;
                    数组1[1] = 0x03;
                    数组1[2] = 0x60;
                    数组1[3] = 0x3C;
                    数组1[4] = 0x00;
                    数组1[5] = 0x06;
                    数组2 = CRC16(数组1);
                    数组3[0] = b;
                    数组3[6] = 数组2[1];
                    数组3[7] = 数组2[0];
                    sp1.Write(数组3, 0, 数组3.Length);
                    Thread.Sleep(50);
                    Byte[] receivedData = new Byte[sp1.BytesToRead];
                    sp1.Read(receivedData, 0, receivedData.Length);
                    if (receivedData[1] == 0x03)
                    {
                        ret.Value = receivedData;
                        sp1.DiscardInBuffer();
                    }
                    else
                    {
                        sp1.DiscardInBuffer();
                    }
                }
                catch (Exception ex)
                {
                    ret.StatusType = EnumVariableStatus.Bad;
                    ret.Message = $"读取失败,{ex.Message}";
                    _logger.Error(ex, $"读取失败{ioArg.Address}");
                }
            }
            else
            {
                ret.StatusType = EnumVariableStatus.Bad;
                ret.Message = "连接失败";
            }

            return ret;
        }
        public DriverReturnValueModel Read(DriverAddressIoArgModel ioArg)
        {
            throw new NotImplementedException();
        }

        public Task<RpcResponse> WriteAsync(string RequestId, string Method, DriverAddressIoArgModel ioArg)
        {
            throw new NotImplementedException();
        }

        public void Dispose()
        {
            try
            {
                sp1?.Dispose();

                // Suppress finalization.
                GC.SuppressFinalize(this);

                _logger.Info($"Device:[{_device}],Dispose()");
            }
            catch (Exception ex)
            {
                _logger.Error($"Device:[{_device}],Dispose(),Error", ex);
            }
        }
    }
}
